package clickhouse.service.impl;

import clickhouse.config.DataConfig;
import clickhouse.service.IClickHouseOperation;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;


public abstract class ClickHouseDataBase implements IClickHouseOperation {
	private static volatile ClickHouseDataBase clickHouseDatabase;
	private Map<String,Map<String,String>> tableFieldMeta=new HashMap<>();
	public static ClickHouseDataBase getInstance() {
		if (clickHouseDatabase == null) {
			synchronized (ClickHouseDataBase.class) {
				if (clickHouseDatabase == null) {
					try {
						// clickHouseDatabase = new clickhouse.service.impl.ClickHouseJdbcCommon();

						// 根据配置 切换不同实现
						Class c = Class.forName(DataConfig.getProperty("clickhouse.implementclass"), false,
								ClickHouseDataBase.class.getClassLoader());
						java.lang.reflect.Constructor m = c.getDeclaredConstructor();
						m.setAccessible(true);
						clickHouseDatabase = (ClickHouseDataBase) m.newInstance();
					} catch (Exception ex) {
						ex.printStackTrace();
					}
				}
			}
		}
		return clickHouseDatabase;
	}
	/**
	 * 从结果集提取数据到List
	 * 
	 * @param rs
	 * @return
	 * @throws SQLException
	 */
	protected List<Map<String, Object>> retriveDataFromResultSet(ResultSet rs) {
		try{
			List<Map<String, Object>> result = new ArrayList<>();
			int columnCount = rs.getMetaData().getColumnCount();
			Map<String, Object> mapRow;
			while (rs.next()) {
				mapRow = new HashMap<>();
				for (int i = 1; i <= columnCount; i++) {
					mapRow.put(rs.getMetaData().getColumnName(i), rs.getObject(i));
				}
				result.add(mapRow);
			}
			return result;
		}catch (Exception ex){
			ex.printStackTrace();
		}
		return Collections.emptyList();
	}

	/**
	 * 读取表的结构信息
	 * @param tblName 表名
	 * @param resultSetMetaData 表结构元数据
	 * @return 键：字段名，值：字段类型
	 */
	protected Map<String,String> getTableFieldMeta(String tblName, ResultSetMetaData resultSetMetaData){
		try{
			Map<String,String> result=tableFieldMeta.get(tblName);
			if(result==null){
				result=new HashMap<>();
				int columnCount=resultSetMetaData.getColumnCount();
				for (int i = 1; i <= columnCount; i++) {
					result.put(resultSetMetaData.getColumnName(i), resultSetMetaData.getColumnTypeName(i));
				}
				tableFieldMeta.put(tblName,result);
			}
			return result;
		}catch (Exception ex){
			ex.printStackTrace();
		}
		return Collections.emptyMap();
	}

	/**
	 * 构造update字符串
	 * @param updateValues 字段名与字段值 键值对
	 * @param fieldMeta 字段名与字段类型 键值对
	 * @return
	 */
	protected String constructUpdateStr(Map<String, Object> updateValues, Map<String, String> fieldMeta) {
		StringBuilder sb=new StringBuilder();
		String columnType;
		for(Map.Entry<String,Object> entry:updateValues.entrySet()){
				columnType=fieldMeta.get(entry.getKey());
				sb.append(entry.getKey());
				sb.append("=");
				sb.append(getPre(columnType));
				sb.append(convertValue(entry.getValue(),columnType));
				sb.append(getPre(columnType));
				sb.append(",");
		}
		return sb.substring(0,sb.length()-1);
	}

	//判断字段是否日期
	private boolean judgeIsDate(String type){
		if(type!=null&&type.startsWith("Date")){
			return true;
		}
		return false;
	}
	//判断字段是否字符串
	private boolean judgeIsString(String type){
		if(type!=null&&type.startsWith("String")){
			return true;
		}
		return false;
	}
	/**
	 * 根据字段类型，作相应转化
	 * @param v
	 * @param type
	 * @return
	 */
	protected Object convertValue(Object v,String type) {
		SimpleDateFormat sdf;
		if(judgeIsDate(type)){
			if(!(v instanceof Date)){
				throw new RuntimeException("字段值必须是java.util.Date类型");
			}
			if(type.startsWith("DateTime")){
				sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				return sdf.format((Date)v);
			}
			else if(type.contains("Date")){
				sdf=new SimpleDateFormat("yyyy-MM-dd");
				return sdf.format((Date)v);
			}
		}
		return v;
	}
	private String getPre(String type) {
		if(judgeIsString(type)||judgeIsDate(type)){
			return "'";
		}
		return "";
	}
	@Override
	public void batchInsertData(ClickHouseWrap clickHouseWrap,String tableName, List<Map<String, Object>> fieldValues) {

	}

	@Override
	public void batchInsertData(String tableName, List<Map<String, Object>> fieldValues) {

	}

	@Override
	public void insertData(String tableName, Map<String, Object> fieldValues) {
		batchInsertData(tableName, Arrays.asList(fieldValues));
	}
	@Override
	public void insertData(ClickHouseWrap clickHouseWrap, String tableName, Map<String, Object> fieldValues){
		batchInsertData(clickHouseWrap,tableName, Arrays.asList(fieldValues));
	}
	@Override
	public List<Map<String, Object>> getListMapFromSql(ClickHouseWrap clickHouseWrap, String sql) {
		return null;
	}
	@Override
	public int deleteData(ClickHouseWrap clickHouseWrap, String tblName,String clause){
		return -1;
	}
	@Override
	public int updateData(ClickHouseWrap clickHouseWrap, String tableName,Map<String,Object> updateValues,String clause){
		return -1;
	}
	@Override
	public List<Map<String, Object>> getListMapFromSql(String sql) {
		return null;
	}
	@Override
	public int deleteData(String tblName,String clause){
		return -1;
	}
	@Override
	public int updateData(String tableName,Map<String,Object> updateValues,String clause){
		return -1;
	}
	@Override
	public ClickHouseWrap getClickHouseWrap() {
		return null;
	}

	@Override
	public void closeDataBase(ClickHouseWrap clickHouseWrap) {

	}
}
